package com.custom.base.base

import android.app.Activity
import android.util.SparseArray
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import com.custom.base.manager.SDSelectManager
import java.util.*

/**
 * 作者：
 * 时间：2020/5/11
 * 描述：
 **/
abstract class BaseSDAdapter<T>(listModel: MutableList<T>, var mActivity: Activity?) : BaseAdapter() {
    private var isCountSize = false
    private var countSize = 2

    protected var mListModel: MutableList<T> = ArrayList()
    protected var mInflater: LayoutInflater

    /**
     * 保存每个position的parentView
     */
    private val mMapPositionParentView = SparseArray<ViewGroup>()
    /**
     * 保存每个itemView对应的position
     */
    private val mMapViewPosition = LinkedHashMap<View, Int>()
    /**
     * 点击回调
     */
    private var mListenerItemClick: ItemClickListener<T>? = null

    /**
     * 选择器
     */
    val mSelectManager: SDSelectManager<T> =
        SDSelectManager()
        get() = field

    private val mListenerItemState: ItemStateListener<T>? = null

    /**
     * 获得adapter的实体集合给adapter设置数据
     *
     * @param listModel
     */
    var data: MutableList<T>
        get() = mListModel
        set(listModel) {
            this.mListModel = listModel
            mSelectManager.setItems(mListModel)
            synchronizedSelected()
        }

    /**
     * 初始化
     */
    init {
        mSelectManager.mMode = SDSelectManager.Mode.SINGLE
        /**
         * 默认选择管理器监听
         */
        mSelectManager.setListener(object : SDSelectManager.SDSelectManagerListener<T>{
            override fun onNormal(index: Int, item: T?) {
                onNormalItem(index, item)
                mListenerItemState?.onNormal(index, item)
            }

            override fun onSelected(index: Int, item: T?) {
                onSelectedItem(index, item)
                mListenerItemState?.onSelected(index, item)
            }
        })
        data = listModel
        this.mInflater = mActivity!!.layoutInflater
    }

    /**
     * 设置回调
     */
    fun setListenerItemClick(listenerItemClick: ItemClickListener<T>) {
        this.mListenerItemClick = listenerItemClick
    }

    /**
     * 开始回调
     */
    fun startListenerItemClick(position: Int, model: T, convertView: View?) {
        mListenerItemClick?.onClick(position, model, convertView)
    }

    fun getmInflater(): LayoutInflater? {
        return this.mInflater
    }

    fun getmActivity(): Activity? {
        return mActivity
    }

    /**
     * item被置为正常状态的时候回调
     *
     * @param position
     * @param item
     */
    protected open fun onNormalItem(position: Int, item: T?) {
        if (item is SDSelectable) {
            val selectable = item as SDSelectable
            selectable.isSelected = false
        }
        updateItem(position)
    }

    /**
     * item被置为选中状态的时候回调
     *
     * @param position
     * @param item
     */
    protected open fun onSelectedItem(position: Int, item: T?) {
        if (item is SDSelectable) {
            val selectable = item as SDSelectable
            selectable.isSelected = true
        }
        updateItem(position)
    }

    /**
     * 将实体中的选中状态同步到选择管理器中，常用于设置数据后调用，只有实体实现了SDSelectable接口调用此方法才有效
     */
    private fun synchronizedSelected() {
        for (model in mListModel) {
            synchronizedSelected(model)
        }
    }

    private fun synchronizedSelected(model: T) {
        if (model is SDSelectable) {
            val sModel = model as SDSelectable
            if (mSelectManager.isSelected(model) != sModel.isSelected) {
                mSelectManager.setSelected(model, sModel.isSelected)
            }
        }
    }

    /**
     * 更新adapter的数据集合，并刷新adapter
     *
     * @param listModel
     */
    fun updateData(listModel: MutableList<T>) {
        data = listModel
        notifyDataSetChanged()
    }

    override fun notifyDataSetChanged() {
        clearViews()
        super.notifyDataSetChanged()
    }

    private fun clearViews() {
        mMapPositionParentView.clear()
        mMapViewPosition.clear()
    }

    /**
     * 添加数据
     * @param notify 是否刷新
     */
    fun appendData(listModel: MutableList<T>?, notify: Boolean = true) {
        listModel?.apply {
            if (isNotEmpty()) {
                mListModel.addAll(this)
                mSelectManager.appendItems(listModel, false)
                synchronizedSelected()
                if (notify) notifyDataSetChanged()
            }
        }
    }
    /**
     * 添加数据
     * @param notify 是否刷新
     */
    fun appendData(model: T?, notify: Boolean = true) {
        model?.apply {
            mListModel.add(this)
            mSelectManager.appendItem(model, false)
            synchronizedSelected(model)
            if (notify) notifyDataSetChanged()
        }
    }

    /**
     * 判断position 是否越界
     */
    fun isPositionLegal(position: Int): Boolean {
        return mListModel.isNotEmpty() && position >= 0 && position < mListModel.size
    }

    override fun getCount(): Int {
        return if (isCountSize) {
            if (mListModel.size > countSize) countSize else mListModel.size
        } else {
            mListModel.size
        }
    }

    /**
     * 是否是最后一个
     * @param position
     * @return
     */
    fun isLastPosition(position: Int): Boolean {
        return position == count - 1
    }

    /**
     * 设置强制设置Count的size，默认为2
     *
     * @param size
     */
    fun setCountSize(size: Int) {
        countSize = size
        setIsCountSize(true)
    }

    /**
     * 设置是否强制设置Count的size，默认false
     *
     * @param isCountSizes
     */
    fun setIsCountSize(isCountSizes: Boolean) {
        isCountSize = isCountSizes
    }

    override fun getItem(position: Int): T? {
        return if (isPositionLegal(position)) {
            mListModel[position]
        } else {
            null
        }
    }


    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? {
        var convertView = convertView
        beforeOnGetView(position, convertView, parent)
        convertView = onGetView(position, convertView, parent)
        afterOnGetView(position, convertView, parent)
        return convertView
    }


    protected fun beforeOnGetView(position: Int, convertView: View?, parent: ViewGroup?) {
        mMapPositionParentView.put(position, parent)
    }

    /**
     * 重写此方法，不要重写public View getView(int position, View convertView, ViewGroup
     * parent)方法
     *
     * @param position
     * @param convertView
     * @param parent
     * @return
     */

    protected open fun onGetView(position: Int, convertView: View?, parent: ViewGroup?): View? {
        return convertView
    }

    protected fun afterOnGetView(position: Int, convertView: View?, parent: ViewGroup?) {
        mListenerItemClick?.apply {
            convertView?.setOnClickListener {
                mListenerItemClick?.onClick(position, mListModel[position], convertView)
            }
        }
        putItemView(position, convertView)
    }

    private fun putItemView(position: Int, view: View?) {
        view?.apply {
            mMapViewPosition[this] = position
        }
    }

    /**
     * 刷新position对应的itemView
     *
     * @param position
     */
    fun updateItem(position: Int) {
        val itemView = getItemView(position)
        itemView?.apply {
            onUpdateView(position, itemView, null, getItem(position))
        }
    }

    /**
     * 刷新position对应的itemView，数据会根据提供的model来绑定，并替换原list中该位置的model
     *
     * @param position
     * @param model
     */
    fun updateItem(position: Int, model: T) {
        if (isPositionLegal(position)) {
            mListModel[position] = model
            updateItem(position)
        }
    }

    /**
     * 刷新model对应的itemView
     *
     * @param model
     */
    fun updateItem(model: T) {
        updateItem(indexOf(model))
    }

    /**
     * 获得该position对应的itemView
     *
     * @param position
     * @return
     */
    fun getItemView(position: Int): View? {
        var itemView: View? = null
        for ((key, value) in mMapViewPosition) {
            if (Integer.valueOf(position) == value) {
                itemView = key
                break
            }
        }
        return itemView
    }

    /**
     * 获得该position对应到parentView
     *
     * @param position
     * @return
     */
    fun getItemParent(position: Int): ViewGroup {
        return mMapPositionParentView.get(position)
    }

    /**
     * 若重写此方法，则应该把需要刷新的逻辑写在重写方法中，然后不调用super的方法，此方法会在调用updateItem方法刷新某一项时候触发
     *
     * @param position
     * @param convertView
     * @param parent
     * @param model
     */
    protected fun onUpdateView(position: Int, convertView: View, parent: ViewGroup?, model: T?) {
        getView(position, convertView, null)
    }

    /**
     * 移除该position对应的项
     *
     * @param position
     */
    fun removeItem(position: Int) {
        if (isPositionLegal(position)) {
            mListModel.removeAt(position)
            notifyDataSetChanged()
        }
    }

    /**
     * 移除该model对应的项
     *
     * @param t
     */
    fun removeItem(t: T) {
        removeItem(indexOf(t))
    }

    fun indexOf(t: T?): Int {
        var index = -1
        t?.apply {
            index = mListModel.indexOf(this)
        }
        return index
    }

    interface ItemClickListener<T> {
        fun onClick(position: Int, item: T, view: View?)
    }

    interface SDSelectable {
        var isSelected: Boolean
    }

    interface ItemStateListener<T> {
        fun onNormal(position: Int, item: T?)
        fun onSelected(position: Int, item: T?)
    }

    companion object {
        operator fun <V : View> get(id: Int, convertView: View): V {
            var viewHolder: SparseArray<View>? = convertView.tag as SparseArray<View>
            if (viewHolder == null) {
                viewHolder = SparseArray()
                convertView.tag = viewHolder
            }
            var childView: View? = viewHolder.get(id)
            if (childView == null) {
                childView = convertView.findViewById(id)
                viewHolder.put(id, childView)
            }
            return childView as V
        }

        fun <V : View> find(id: Int, convertView: View?): V {
            return convertView?.findViewById<View>(id) as V
        }
    }
}